import { BaseSysParamEntity } from './../../base/entity/sys/param';
import { Inject, Provide } from '@midwayjs/core';
import { BaseService, CoolCommException } from '@cool-midway/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Between, Repository } from 'typeorm';
import { OrderOrderEntity } from '../entity/order';
import { DeviceDeviceEntity } from '../../device/entity/device';
import { UserInfoEntity } from '../../user/entity/info';
import { FinanceProfitService } from '../../finance/service/profit';
import { Context } from '@midwayjs/koa';
import { GamePackageEntity } from '../entity/package';
import { UserRelationEntity } from '../../user/entity/user_relation';
import { UserInfoService } from '../../user/service/info';
import { PluginService } from '../../plugin/service/info';
import { FinanceProfitEntity } from '../../finance/entity/profit';
import { OrderProfitQueue } from '../queue/profit';
import axios from 'axios';
import { LAKALA_PAY_URL } from '../../../comm/constant';
import { Utils } from '../../../comm/utils';
import moment = require('moment');
import { randomUUID } from '@midwayjs/core/dist/util/uuid';

/**
 * 订单服务类，处理订单相关的业务逻辑，包括订单创建、分佣计算以及订单统计等。
 */
@Provide()
export class OrderOrderService extends BaseService {
  @Inject()
  pluginService: PluginService;

  /** 订单实体仓库，用于订单数据的增删改查 */
  @InjectEntityModel(OrderOrderEntity)
  orderOrderEntity: Repository<OrderOrderEntity>;

  /** 设备实体仓库，用于查询设备信息 */
  @InjectEntityModel(DeviceDeviceEntity)
  deviceDeviceService: Repository<DeviceDeviceEntity>;

  /** 用户信息实体仓库，用于查询和更新用户信息，如余额、分佣比例等 */
  @InjectEntityModel(UserInfoEntity)
  userInfoEntity: Repository<UserInfoEntity>;

  @InjectEntityModel(BaseSysParamEntity)
  BaseSysParamEntity: Repository<BaseSysParamEntity>;

  /** Koa Context 对象，用于获取请求上下文信息，如当前登录用户 */
  @Inject()
  ctx: Context;

  @Inject()
  financeProfitService: FinanceProfitService;

  @InjectEntityModel(FinanceProfitEntity)
  FinanceProfitEntity: Repository<FinanceProfitEntity>;

  @InjectEntityModel(GamePackageEntity)
  gamePackageEntity: Repository<GamePackageEntity>;

  // 用户关系表
  @InjectEntityModel(UserRelationEntity)
  userRelationEntity: Repository<UserRelationEntity>;

  @Inject()
  userInfoService: UserInfoService;

  @Inject()
  orderProfitQueue: OrderProfitQueue;

  @Inject()
  utils: Utils;

  /**
   * 按日期范围统计订单数据。
   * 包括每日订单总数和总金额。
   * @param {string} startDate 开始日期，格式如 'YYYY-MM-DD'
   * @param {string} endDate 结束日期，格式如 'YYYY-MM-DD'
   * @returns {Promise<Array<{date: string, total: number, totalAmount: number}>>} 返回按日期聚合的统计结果数组。
   */

  async statisticsByDate(startDate: string, endDate: string) {
    const userId = this.ctx?.user?.id;

    // 先查用户的角色
    const userInfo = await this.userInfoService.person(userId);

    console.log('userInfo', userInfo);

    // 如果是代理
    if (userInfo && userInfo.role === 1) {
      const paid = await this.orderOrderEntity
        .createQueryBuilder('order')
        .select([
          'DATE_FORMAT(createTime, "%Y-%m-%d") as date',
          'COUNT(*) as total',
          'SUM(payAmount) as totalAmount',
          'SUM(gameCount) as coinCount',
        ])
        .where('createTime BETWEEN :startDate AND :endDate', {
          startDate,
          endDate,
        })
        .andWhere('payStatus = :status', { status: 1 })
        .andWhere('deviceBindAgentId = :deviceBindAgentId', {
          deviceBindAgentId: userInfo?.id,
        })
        .groupBy('DATE_FORMAT(createTime, "%Y-%m-%d")')
        .orderBy('date', 'ASC')
        .getRawMany();

      const refunds = await this.orderOrderEntity
        .createQueryBuilder('order')
        .select([
          'DATE_FORMAT(refundTime, "%Y-%m-%d") as date',
          'COUNT(*) as refundCount',
          'SUM(refundAmount) as refundAmount',
        ])
        .where('refundTime BETWEEN :startDate AND :endDate', {
          startDate,
          endDate,
        })
        .andWhere('deviceBindAgentId = :deviceBindAgentId', {
          deviceBindAgentId: userInfo?.id,
        })
        .groupBy('DATE_FORMAT(refundTime, "%Y-%m-%d")')
        .getRawMany();

      const refundMap = new Map(refunds.map(r => [r.date, r]));
      return paid.map(p => ({
        ...p,
        refundCount: Number(refundMap.get(p.date)?.refundCount || 0),
        refundAmount: Number(refundMap.get(p.date)?.refundAmount || 0),
      }));
    }

    // 如果是商户
    if (userInfo && userInfo.role === 2) {
      const paid = await this.orderOrderEntity
        .createQueryBuilder('order')
        .select([
          'DATE_FORMAT(createTime, "%Y-%m-%d") as date',
          'COUNT(*) as total',
          'SUM(payAmount) as totalAmount',
          'SUM(gameCount) as coinCount',
        ])
        .where('createTime BETWEEN :startDate AND :endDate', {
          startDate,
          endDate,
        })
        .andWhere('payStatus = :status', { status: 1 })
        .andWhere('deviceBindUserId = :deviceBindUserId', {
          deviceBindUserId: userInfo?.id,
        })
        .groupBy('DATE_FORMAT(createTime, "%Y-%m-%d")')
        .orderBy('date', 'ASC')
        .getRawMany();

      const refunds = await this.orderOrderEntity
        .createQueryBuilder('order')
        .select([
          'DATE_FORMAT(refundTime, "%Y-%m-%d") as date',
          'COUNT(*) as refundCount',
          'SUM(refundAmount) as refundAmount',
        ])
        .where('refundTime BETWEEN :startDate AND :endDate', {
          startDate,
          endDate,
        })
        .andWhere('deviceBindUserId = :deviceBindUserId', {
          deviceBindUserId: userInfo?.id,
        })
        .groupBy('DATE_FORMAT(refundTime, "%Y-%m-%d")')
        .getRawMany();

      const refundMap = new Map(refunds.map(r => [r.date, r]));
      return paid.map(p => ({
        ...p,
        refundCount: Number(refundMap.get(p.date)?.refundCount || 0),
        refundAmount: Number(refundMap.get(p.date)?.refundAmount || 0),
      }));
    }

    if (userInfo && userInfo.role === 3) {
      const paid = await this.orderOrderEntity
        .createQueryBuilder('order')
        .select([
          'DATE_FORMAT(createTime, "%Y-%m-%d") as date',
          'COUNT(*) as total',
          'SUM(payAmount) as totalAmount',
          'SUM(gameCount) as coinCount',
        ])
        .where('createTime BETWEEN :startDate AND :endDate', {
          startDate,
          endDate,
        })
        .andWhere('payStatus = :status', { status: 1 })
        .groupBy('DATE_FORMAT(createTime, "%Y-%m-%d")')
        .orderBy('date', 'ASC')
        .getRawMany();

      const refunds = await this.orderOrderEntity
        .createQueryBuilder('order')
        .select([
          'DATE_FORMAT(refundTime, "%Y-%m-%d") as date',
          'COUNT(*) as refundCount',
          'SUM(refundAmount) as refundAmount',
        ])
        .where('refundTime BETWEEN :startDate AND :endDate', {
          startDate,
          endDate,
        })
        .groupBy('DATE_FORMAT(refundTime, "%Y-%m-%d")')
        .getRawMany();

      const refundMap = new Map(refunds.map(r => [r.date, r]));
      return paid.map(p => ({
        ...p,
        refundCount: Number(refundMap.get(p.date)?.refundCount || 0),
        refundAmount: Number(refundMap.get(p.date)?.refundAmount || 0),
      }));
    }
  }

  // 发送mqtt消息
  async sendMqttMessage({ deviceNo, orderUUid, gameCount, device }) {
    // 获取插件实例
    const instance = await this.pluginService.getInstance('mqtt');

    instance.publish(
      `Service/${deviceNo}`,
      JSON.stringify({
        num: orderUUid,
        value: gameCount,
        device,
      })
    );
  }

  /**
   * 购买游戏币
   * @param packageId 套餐ID
   * @param payAmount 支付金额
   * @param deviceNo 设备号
   * @param userId 用户ID
   * @param openId openId
   * @param payType 支付方式 1：微信支付 2：支付宝支付
   */
  async buyGameCoin(params: {
    packageId?: number;
    payAmount?: number;
    userId?: number;
    deviceNo: string;
    openId: string;
    payType: number;
  }): Promise<any> {
    const {
      packageId,
      payAmount,
      userId,
      deviceNo,
      openId,
      payType = 1,
    } = params;

    // 游戏次数，默认是金额
    let gameCount = payAmount / 100;

    /* 设备号是必填的 */
    if (!deviceNo) {
      throw new CoolCommException('设备号是必填的');
    }

    // 使用正则分割数字和字母
    const parts = deviceNo.split(/(?<=\d)(?=[A-Za-z])|(?<=[A-Za-z])(?=\d)/);

    console.log('deviceNumber', {
      deviceNumber: parts[0],
      deviceNo,
      type: parts[1],
    });

    //  先找到设备的信息
    const deviceInfo = await this.deviceDeviceService.findOneBy({
      deviceNo: parts[0],
    });

    // 如果设备不存在
    if (!deviceInfo) {
      throw new CoolCommException('设备不存在，请先绑定设备');
    }

    // 获取到设备的最后在线时间，判断最后在线时间是否超过120秒
    if (
      deviceInfo.lastOnlineTime &&
      deviceInfo.lastOnlineTime + 180 < Date.now() / 1000
    ) {
      throw new CoolCommException('设备已离线');
    }

    // 如果设备是离线状态
    if (deviceInfo.deviceStatus !== 1) {
      throw new CoolCommException('设备已离线');
    }

    // 通过deviceInfo?.userId找到设备绑定人的信息
    const deviceBindUserInfo = await this.userInfoEntity.findOneBy({
      id: deviceInfo.userId,
    });

    if (!deviceBindUserInfo?.merchantNo) {
      throw new CoolCommException('商户号不存在，请联系管理员');
    }

    if (!deviceBindUserInfo?.terminalNo) {
      throw new CoolCommException('终端号不存在，请联系管理员');
    }

    let gamePackage: GamePackageEntity = null;
    /* 如果有传packageId，则根据packageId查询套餐 */
    if (packageId) {
      gamePackage = await this.gamePackageEntity.findOneBy({
        id: packageId,
      });
      if (!gamePackage) {
        throw new CoolCommException('游戏币套餐不存在');
      }
    }

    const orderUUid = this.generateOrderNo();

    // 如果是游戏币套餐
    if (gamePackage) {
      // 游戏次数
      gameCount = gamePackage?.gameCount;
    }

    // 单笔订单不能超出300
    if ((gamePackage?.packagePrice || payAmount) * 1 > 30000) {
      throw new CoolCommException('单笔订单不能超出300元');
    }

    const startOfDay = new Date();
    startOfDay.setHours(0, 0, 0, 0); // 当天开始时间

    const endOfDay = new Date();
    endOfDay.setHours(23, 59, 59, 999); // 当天结束时间

    // 查询当天订单中，openId是 当前用户的订单，计算其超出了3000元
    const totalAmount = await this.orderOrderEntity.sum('payAmount', {
      openId,
      createTime: Between(startOfDay, endOfDay),
      payStatus: 1,
    });

    // 如果订单totalAmount金额超出3000，返回false
    if (totalAmount > 300000) {
      throw new CoolCommException('当天下单已满3000元，不能再下单了');
    }

    // 创建订单
    const order = new OrderOrderEntity();
    order.orderNo = orderUUid; // 生成唯一订单号
    order.payAmount = (gamePackage?.packagePrice || payAmount) * 1;
    order.payStatus = 0; // 待支付
    order.payType = payType;
    order.payUserId = userId;
    order.deviceBindUserId = deviceInfo?.userId;
    order.deviceBindAgentId = deviceInfo?.agentId;
    order.deviceNo = deviceNo;
    order.packageContent = gamePackage ? JSON.stringify(gamePackage) : '';
    order.isComplete = false;
    order.gameCount = gameCount;
    order.openId = openId;

    // 插入order
    // await this.orderOrderEntity.insert(order);

    const _body =
      payType === 1
        ? this.utils.getRequestWxPay({
            openId: openId,
            orderUUid: orderUUid,
            payAmount: order.payAmount,
            merchantNo: deviceBindUserInfo?.merchantNo,
            terminalNo: deviceBindUserInfo?.terminalNo,
          })
        : this.utils.getRequestZFBPay({
            openId: openId,
            orderUUid: orderUUid,
            payAmount: order.payAmount,
            merchantNo: deviceBindUserInfo?.merchantNo,
            terminalNo: deviceBindUserInfo?.terminalNo,
          });

    try {
      // 请求
      const response = await axios.post(
        'https://s2.lakala.com/api/v3/labs/trans/preorder',
        _body,
        {
          headers: {
            'Content-Type': 'application/json',
            Accept: 'application/json',
            Authorization: this.utils.createAuthorization(_body),
          },
        }
      );

      console.log('responseresponseresponse', response.data);

      if (response.data.code === 'BBS11000') {
        return new CoolCommException(`${response.data.msg}`);
      }

      // 使用任务队列进行分润
      if (deviceInfo?.userId) {
        // await this.orderProfitQueue.add({
        //   deviceInfo,
        //   orderNo: order.orderNo,
        //   payAmount: order.payAmount,
        // });
        // console.log(`分润任务已加入队列 - 订单号: ${order.orderNo}`);
      }

      // 记录订单
      await this.orderOrderEntity.save(order);

      return response.data;
    } catch (error) {
      console.error('\n=== 请求失败 ===', error);
    }
  }

  /**
   * 生成唯一订单号
   */
  private generateOrderNo(): string {
    const now = new Date();
    const year = now.getFullYear();
    const month = (now.getMonth() + 1).toString().padStart(2, '0');
    const day = now.getDate().toString().padStart(2, '0');
    const hours = now.getHours().toString().padStart(2, '0');
    const minutes = now.getMinutes().toString().padStart(2, '0');
    const seconds = now.getSeconds().toString().padStart(2, '0');
    const milliseconds = now.getMilliseconds().toString().padStart(3, '0');
    const random = Math.floor(Math.random() * 9000) + 1000; // 4位随机数
    return `${year}${month}${day}-${hours}${minutes}${seconds}${milliseconds}-${random}`;
  }

  // 注意：分润计算已移至队列处理 (OrderProfitQueue)
  // 这样可以避免阻塞主要的支付流程，提高系统性能

  // 支付成功后
  async paySuccess(data: any) {
    // 查看当前订单是否存在
    const order = await this.orderOrderEntity.findOneBy({
      orderNo: data?.out_trade_no,
    });

    // 使用正则分割数字和字母
    const parts = order?.deviceNo.split(
      /(?<=\d)(?=[A-Za-z])|(?<=[A-Za-z])(?=\d)/
    );

    // const [deviceNumber, type] = order?.deviceNo.split(
    //   order.deviceNo.includes('%23') ? '%23' : '%2523'
    // );

    // 如果订单存在，则更新订单状态，并且进行投币操作
    if (order?.payStatus === 0) {
      // 发送mqtt请求
      this.sendMqttMessage({
        // deviceNo: order?.deviceNo,
        deviceNo: parts[0],
        orderUUid: order?.orderNo,
        gameCount: order?.gameCount || 0,
        device: parts[1],
      });

      this.orderOrderEntity.update(
        { orderNo: data?.out_trade_no },
        { payStatus: 1 }
      );
    }

    if (order) {
      return 'ok';
    } else {
      return '订单不存在';
    }
  }

  // 手动补币
  async manualAdd(params) {
    const parts = params?.deviceNo.split(
      /(?<=\d)(?=[A-Za-z])|(?<=[A-Za-z])(?=\d)/
    );

    // 获取插件实例
    const instance = await this.pluginService.getInstance('mqtt');

    try {
      instance.publish(
        `Service/${parts[0]}`,
        JSON.stringify({
          num: randomUUID(),
          value: params?.gameCount,
          device: parts[1],
        })
      );

      return 'ok';
    } catch (error) {
      return 'error';
    }

    // this.sendMqttMessage({
    //   deviceNo: parts[0],
    //   orderUUid: 0,
    //   gameCount: params?.gameCount,
    //   device: parts[1],
    // });
  }

  async manualAddByOrderNo(params) {
    const { orderNo } = params;
    const order = await this.orderOrderEntity.findOneBy({ orderNo });
    if (!order) {
      throw new CoolCommException('订单不存在');
    }
    const now = Date.now();
    const ct = new Date(order.createTime).getTime();
    if (now - ct > 20 * 60 * 1000) {
      throw new CoolCommException('订单已超过20分钟，不能补币');
    }
    const parts = order.deviceNo.split(
      /(?<=\d)(?=[A-Za-z])|(?<=[A-Za-z])(?=\d)/
    );
    await this.sendMqttMessage({
      deviceNo: parts[0],
      orderUUid: order.orderNo,
      gameCount: order.gameCount || 0,
      device: parts[1],
    });
    return 'ok';
  }

  /* 退款 */
  async refund(params) {
    /* 获取传进来的订单编号 */
    const { orderNo } = params;

    /* 从订单编号去查对应商户的信息 */
    const order = await this.orderOrderEntity.findOneBy({
      orderNo,
    });

    /* 判断订单是否存在 */
    if (!order) {
      throw new CoolCommException('订单不存在');
    }

    const { deviceBindUserId, payAmount } = order;
    console.log('payAmount', payAmount);

    /* 通过设备归属人去查商户号 */
    const deviceBindUserInfo = await this.userInfoEntity.findOneBy({
      id: deviceBindUserId,
    });

    const reqTime = moment().format('YYYYMMDDHHmmss');

    const _body = {
      req_time: reqTime,
      version: '3.0',
      req_data: {
        merchant_no: deviceBindUserInfo?.merchantNo,
        term_no: deviceBindUserInfo?.terminalNo,
        out_trade_no: orderNo,
        origin_out_trade_no: orderNo,
        refund_amount: payAmount * 1,
        refund_reason: '退款',
        location_info: {
          request_ip: '39.108.162.25',
        },
        notify_url: 'https://ryxkeji.com/api/app/order/order/callback',
      },
    };

    try {
      // 请求
      const response = await axios.post(
        'https://s2.lakala.com/api/v3/labs/relation/refund',
        _body,
        {
          headers: {
            'Content-Type': 'application/json',
            Accept: 'application/json',
            Authorization: this.utils.createAuthorization(_body),
          },
        }
      );

      console.log('退款结果', response.data, "orderNo" , orderNo);
      if (response.data.code === 'BBS00000') {
        // 更新订单状态
        await this.orderOrderEntity.update(
          { orderNo },
          { payStatus: 3, refundTime: new Date(), refundAmount: payAmount }
        );
      }

      return response.data;

      console.log('退款结果', response);
    } catch (e) {
      console.log('退款结果', e);
      return e.response.data;

      //TODO handle the exception
    }
  }

  async sumByFilterAdmin(params: any): Promise<number> {
    const qb = this.orderOrderEntity.createQueryBuilder('a')
      .select('SUM(a.payAmount)', 'total');

    const {
      keyWord,
      payStatus,
      isComplete,
      deviceBindUserId,
      deviceBindAgentId,
      deviceNo,
      createTime,
      endTime
    } = params || {};

    if (keyWord) {
      qb.andWhere('a.orderNo LIKE :kw', { kw: `%${keyWord}%` });
    }

    if (payStatus !== undefined && payStatus !== null && payStatus !== '') {
      qb.andWhere('a.payStatus = :payStatus', { payStatus });
    }

    if (isComplete !== undefined && isComplete !== null && isComplete !== '') {
      qb.andWhere('a.isComplete = :isComplete', { isComplete });
    }

    if (deviceBindUserId) {
      qb.andWhere('a.deviceBindUserId = :deviceBindUserId', { deviceBindUserId });
    }

    if (deviceBindAgentId) {
      qb.andWhere('a.deviceBindAgentId = :deviceBindAgentId', { deviceBindAgentId });
    }

    if (deviceNo) {
      qb.andWhere('a.deviceNo LIKE :deviceNo', { deviceNo: `%${deviceNo}%` });
    }

    if (createTime) {
      qb.andWhere('a.createTime >= :startTime', { startTime: createTime });
    }

    if (endTime) {
      qb.andWhere('a.createTime <= :endTime', { endTime });
    }

    const res = await qb.getRawOne<{ total: string | number }>();
    return Number(res?.total || 0);
  }

  async refundSumByFilterAdmin(params: any): Promise<number> {
    const qb = this.orderOrderEntity.createQueryBuilder('a')
      .select('SUM(a.refundAmount)', 'total');

    const {
      keyWord,
      payStatus,
      isComplete,
      deviceBindUserId,
      deviceBindAgentId,
      deviceNo,
      createTime,
      endTime
    } = params || {};

    if (keyWord) {
      qb.andWhere('a.orderNo LIKE :kw', { kw: `%${keyWord}%` });
    }

    if (payStatus !== undefined && payStatus !== null && payStatus !== '') {
      qb.andWhere('a.payStatus = :payStatus', { payStatus });
    }

    if (isComplete !== undefined && isComplete !== null && isComplete !== '') {
      qb.andWhere('a.isComplete = :isComplete', { isComplete });
    }

    if (deviceBindUserId) {
      qb.andWhere('a.deviceBindUserId = :deviceBindUserId', { deviceBindUserId });
    }

    if (deviceBindAgentId) {
      qb.andWhere('a.deviceBindAgentId = :deviceBindAgentId', { deviceBindAgentId });
    }

    if (deviceNo) {
      qb.andWhere('a.deviceNo LIKE :deviceNo', { deviceNo: `%${deviceNo}%` });
    }

    if (createTime) {
      qb.andWhere('a.createTime >= :startTime', { startTime: createTime });
    }

    if (endTime) {
      qb.andWhere('a.createTime <= :endTime', { endTime });
    }

    const res = await qb.getRawOne<{ total: string | number }>();
    return Number(res?.total || 0);
  }

}
  